/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dnbW.uiW.queryW.modelW;

import dnbW.dbW.PathExpression;
import dnbW.entityW.*;
import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 *
 * @author zhouyong
 */
public class ComparisonNodeObject extends ConditionNodeLeafObject {
    // <editor-fold desc="Path Expression">
    protected PathExpression pathExpression;
    
    public PathExpression getPathExpression() {
        return pathExpression;
    }
    // </editor-fold>

    // <editor-fold desc="Value">
    protected String value;

    public String getValue() {
        return value;
    }
    
    // edit value property, fire the change event without updating oldValue property
    public void setValue(String value) {
        String oldValue2 = this.value;
        this.value = value;

        
    }
    // </editor-fold>

    // <editor-fold desc="Operator">
    protected String operator;

    public String getOperator() {
        return operator;
    }

    // edit operator property, fire the change event without updating oldOperator property
    public void setOperator(String operator) {
        String oldVal = this.operator;
        this.operator = operator;
        //this.propertyChangeSupport.firePropertyChange("operator", oldVal, this.operator);
    }
    // </editor-fold>

    // <editor-fold desc="Old value">
    protected String oldValue;
    
    public String getOldValue() {
        return oldValue;
    }
    // </editor-fold>
    
    // <editor-fold desc="Old operator">
    protected String oldOperator;

    public String getOldOperator() {
        return oldOperator;
    }
    // </editor-fold>

    // <editor-fold desc="Update Code">
    protected int UpdateCode = 0;

    public int getUpdateCode() {
        return UpdateCode;
    }

    public void setUpdateCode(int UpdCode) {
        UpdateCode = UpdCode;
    }
    // </editor-fold>

    public ComparisonNodeObject(DefaultMutableTreeNode node, PathExpression pathExpression, String operator, String value) {
        //super(node);
        this.pathExpression = pathExpression;
        this.value = value;
        this.operator = operator;
    }

    public void setUpdated(int UpdCode, String newVal, String newOp) {
        oldValue = value;
        oldOperator = operator;
        this.setUpdateCode(UpdCode);
        this.setValue(newVal);
        this.setOperator(newOp);
    }

    public boolean isNodeUpdated() {
        return (UpdateCode != 0);
    }

    @Override
    public String toString() {
        return this.getPathExpression().getHumanReadableTextShort() +
                " " +
                this.getOperator() +
                " " + this.getValue();
    }

    /**
     * Builds an XPath expression in which the given output path takes this 
     * path expression (along with value condition) as an predicate
     * @param outputPathExp    Output path
     * @return              XPath expression
     */
    //@Override
    public String getXPath(PathExpression outputPath) {
        // note: this implementation does not support descendant axis
        // and does not support cross database join
        if (!outputPath.getDataSource().equals(this.getPathExpression().getDataSource())) {
            return null;
        }

        StringBuilder result = new StringBuilder();
        List<DefaultMutableTreeNode> list1 = outputPath.getFullPath();
        List<DefaultMutableTreeNode> list2 = this.getPathExpression().getFullPath();

        int lcp = PathExpression.lcp(outputPath, this.getPathExpression());

        // the common prefix of two expressions
        for (int i = 0; i <= lcp; i++) {
            result.append("/");
            result.append(list1.get(i));
        }
        // path expression 2 as a predicate
        result.append("[");
        for (int i = lcp + 1; i < list2.size(); i++) {
            if (i != (lcp + 1)) {
                result.append("/");
            }
            result.append(list2.get(i));
        }
        //  position predicate
        if (this.getPathExpression().getFromIndex() != -1) {
            result.append("[");
            result.append(this.getPathExpression().getFromIndex());
            result.append("]");
        }

        result.append(this.produceSQLValueComparisonString());
        result.append("]"); // close predicate

        // append the remaining part of the output path (first expression)
        for (int i = lcp + 1; i < list1.size(); i++) {
            result.append("/" + list1.get(i));
        }
        return result.toString();
    }

    //@Override
    public String getXPath(PathExpression outputPath, ConditionCluster currentConditionCluster) {
        // note: this implementation does not support descendant axis
        // and does not support cross database join
        if (!outputPath.getDataSource().equals(this.getPathExpression().getDataSource())) {
            return null;
        }

        StringBuilder result = new StringBuilder();
        List<DefaultMutableTreeNode> list1 = outputPath.getFullPath();
        List<DefaultMutableTreeNode> list2 = this.getPathExpression().getFullPath();

        int lcp = PathExpression.lcp(outputPath, this.getPathExpression());

        for (int i = 0; i <= lcp; i++) {
            result.append("/");
            result.append(list1.get(i));
        }
        result.append("[");
        for (int i = lcp + 1; i < list2.size(); i++) {
            if (i != (lcp + 1)) {
                result.append("/");
            }
            result.append(list2.get(i));
        }
        if (this.getPathExpression().getFromIndex() != -1) {
            result.append("[");
            result.append(this.getPathExpression().getFromIndex());
            result.append("]");
        }

        result.append(this.produceSQLValueComparisonString());

//        for (int i = 0; i < currentConditionCluster.size(); i++) {
//            result.append(" and ");
//            ComparisonNodeObject currCondition = (ComparisonNodeObject) currentConditionCluster.getCondition(i);
//            List<DefaultMutableTreeNode> list = currCondition.getPathExpression().getFullPath();
//
//            for (int j = lcp + 1; j < list.size(); j++) {
//                if (j != (lcp + 1)) {
//                    result.append("/");
//                }
//                result.append(list.get(j));
//            }
//
//            result.append(currCondition.produceSQLValueComparisonString());
//        }

        result.append("]");

        for (int i = lcp + 1; i < list1.size(); i++) {
            result.append("/" + list1.get(i));
        }

        return result.toString();
    }

    /**
     * Produces a string for the value comparison (operator + compared value)
     * which could be used in an SQL query string
     * @return
     */
    private String produceSQLValueComparisonString() {
        StringBuilder result = new StringBuilder();

        String op = getOperator();
        String vl = getValue();

        // operator LIKE is equivalent to = %vl%
        if (Operators.LK.equals(op)) {
            vl = "%" + vl + "%";
            op = Operators.EQ;
        }

        // append operator first
        result.append(op);

        // then append value
        if (Operators.EQ.equals(op) || Operators.NE.equals(op) || Operators.LK.equals(op) || Operators.NLK.equals(op)) {
            result.append("'" + vl + "'");
        } else {
            result.append(vl);
        }
        return result.toString();
    }

    //@Override
    public String getXQuery(PathExpression outputPath) {
        return null;
    }

    public Condition getCondition(PathExpression outputPathExp) {
        Path outputPath = Path.buildPathFromPathExp(outputPathExp.getDataSource(), outputPathExp.getFullPathText());
        Condition outputCondition = new Condition(outputPath);
        Path thisPath = Path.buildPathFromPathExp(outputPathExp.getDataSource(), controller.Controller.currentPath.getFullPathText());
        Operator operator = Operator.createOperator(this.operator);
        String value = this.value;
        Condition thisCondition = new Condition(thisPath);
        thisCondition.setValueCondition(operator, value);
        outputCondition.getGroup().addCondition(thisCondition);
        return outputCondition;
    }

//    public Condition getCondition(PathExpression outputPathExp, ConditionCluster cluster) {
//        Path outputPath = Path.buildPathFromPathExp(outputPathExp.getDataSource(), outputPathExp.getFullPathText());
//        Condition outputCondition = new Condition(outputPath);
//        Path thisPath = Path.buildPathFromPathExp(outputPathExp.getDataSource(), this.pathExpression.getFullPathText());
//        Operator operator = Operator.createOperator(this.operator);
//        String value = this.value;
//        Condition thisCondition = new Condition(thisPath);
//        thisCondition.setValueCondition(operator, value);
//        outputCondition.getGroup().addCondition(thisCondition);
//        for (ConditionNodeLeafObject obj : cluster.getConditions()) {
//            if (obj instanceof ComparisonNodeObject) {
//                ComparisonNodeObject other = (ComparisonNodeObject)obj;
//                Path otherPath = Path.buildPathFromPathExp(outputPathExp.getDataSource(), other.getPathExpression().getFullPathText());
//                Operator otherOperator = Operator.createOperator(other.operator);
//                String otherValue = other.value;
//                Condition otherCondition = new Condition(otherPath);
//                otherCondition.setValueCondition(otherOperator, otherValue);
//                thisCondition.getGroup().addCondition(otherCondition);
//            }
//        }
//        return outputCondition;
//    }

    public Condition getConditionForUpdate(PathExpression outputPathExp) {
        Path outputPath = Path.buildPathFromPathExp(outputPathExp.getDataSource(), outputPathExp.getFullPathText());
        Condition outputCondition = new Condition(outputPath);
        Path thisPath = Path.buildPathFromPathExp(outputPathExp.getDataSource(), this.pathExpression.getFullPathText());
        Operator operator = Operator.createOperator(this.operator);
        String value = this.value;
        Condition thisCondition = new Condition(thisPath);
        thisCondition.setValueCondition(operator, value);
        outputCondition.getGroup().addCondition(thisCondition);
        return outputCondition;
    }
}
